package com.yunhan.scc.oms.web.service.impl.excel;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFCellStyle;
import org.apache.poi.hssf.usermodel.HSSFFont;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.hssf.util.HSSFColor;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.util.CellRangeAddress;
/**
* @ClassName: ExportExcelUtil 
* @Description: TODO(Excel 导出工具 我研究发现到处的Excel格式比较简单 但是数据量会比较大，
* 使用JXLS模板方式效率很低，JXLS适合Excel格式复杂但数据量相对比较小的方式。注意：使用这个类需要相应的实体类
* 实现ExcelExportMustImpMethodBean.java 中的方法。可以参考main函数的方式。我尽可能使该工具变得公用。
* 但是很可惜，该工具只能适合少部分业务。) 
* @author YangTao
* @date 2017-4-20 下午3:06:59
 */
public class ExportExcelUtil {
	//测试
	public static void main(String[] args) throws Exception {
		//构建数据
//		List<ExcelExportMustImpMethodBean> list = new ArrayList<>();
		List<ExcelExportMustImpMethodBean> list = new ArrayList<>();
		for(int i = 0; i < 100; i++){
			Studer studer = new Studer();
			studer.setName("name" + i);
			studer.setBanji("四年级一班");
			studer.setBishicj((int)(Math.random() * 100));
			studer.setJishicj((int)(Math.random() * 100));
			list.add(studer);
		}
		long s = System.currentTimeMillis();
		//根据数据生成文件
		ExportExcelUtil excelManage = new ExportExcelUtil();
		excelManage.genExcel(list,"D://workbook.xls");
		System.out.println("耗时:"+(System.currentTimeMillis()-s));
	}
	/**
	 * YangTao 2017年4月20日 15:20:25
	* @Title: genExcel 
	* @Description: TODO(生成Excel，该放法简单，但是需要实体类提供相应的支持。有重载方法可使用) 
	* @param @param beans
	* @param @param filePath
	* @param @throws IllegalAccessException
	* @param @throws IllegalArgumentException
	* @param @throws InvocationTargetException
	* @param @throws IOException
	* @return void
	 */
	public void genExcel(List<? extends ExcelExportMustImpMethodBean> beans, final String filePath) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, IOException{
		genExcel(beans, "", filePath);
	}
	
	public void genExcel(List<? extends ExcelExportMustImpMethodBean> beans,String title, final String filePath) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, IOException{
		if(beans != null && beans.size() > 0){
			ExcelExportMustImpMethodBean studer = beans.get(0);
			String[] head = getExcelHeadByBean(studer);
			genExcel(beans, title ,head,filePath);
		}else{
			//没有数据
			return;
		}
	}
	
	public void genExcel(List<? extends ExcelExportMustImpMethodBean> beans, String[] head,final String filePath) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, IOException{
		genExcel(beans,null,head,filePath);
	}
	
	public void genExcel(List<? extends ExcelExportMustImpMethodBean> beans, String title , String[] head, final String filePath) throws IOException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
		
		if(beans == null || beans.size() == 0){
			//没得数据还导个毛啊
			return;
		}
		
		int rowIndex = 0;
		// 创建HSSFWorkbook对象(excel的文档对象)
		HSSFWorkbook wb = new HSSFWorkbook();
		// 建立新的sheet对象（excel的表单）
		HSSFSheet sheet = wb.createSheet();
		HSSFRow row2 = sheet.createRow(rowIndex);
		row2.setHeight((short)450);//行高
		
		HSSFCellStyle style = wb.createCellStyle();
		//设置边框
		style.setBorderBottom(HSSFCellStyle.BORDER_THIN); //下边框    
		style.setBorderLeft(HSSFCellStyle.BORDER_THIN);//左边框    
		style.setBorderTop(HSSFCellStyle.BORDER_THIN);//上边框    
		style.setBorderRight(HSSFCellStyle.BORDER_THIN);//右边框   
		// 设置这些样式
		style.setAlignment(HSSFCellStyle.ALIGN_CENTER);//水平居中 
		style.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);//垂直居中
		 // 背景色
		//style.setFillForegroundColor(IndexedColors.GREY_40_PERCENT.getIndex());
		style.setFillForegroundColor(new HSSFColor.LIGHT_GREEN().getIndex());
		style.setFillPattern(CellStyle.SOLID_FOREGROUND);
		HSSFFont font = wb.createFont(); 
		font.setFontName("宋体");
		font.setFontHeightInPoints((short)14);// 设置字体大小
		style.setFont(font);
		
		if(title == null || title.equals("")){
		}else{
			// 在sheet里创建第一行，参数为行索引(excel的行)，可以是0～65535之间的任何一个
			HSSFRow row1 = sheet.createRow(rowIndex);
			// 创建单元格（excel的单元格，参数为列索引，可以是0～255之间的任何一个
			HSSFCell cell = row1.createCell(0);
			row1.setHeightInPoints((short) (15.625*4));
	        font.setFontHeightInPoints((short)18);// 设置字体大小
	        style.setFont(font);
	        cell.setCellStyle(style);
			// 设置单元格内容
			cell.setCellValue(title);
			// 合并单元格CellRangeAddress构造参数依次表示起始行，截至行，起始列， 截至列
			sheet.addMergedRegion(new CellRangeAddress(0, 0, 0, head.length));
			++rowIndex;
		}
		
		// 在sheet里创建第二行
		//生成表头内容
		for(int i = 0; i < head.length; i++){
			sheet.setColumnWidth(i, 17 * 450);//列宽
			// 创建单元格并设置单元格内容
			HSSFCell cell1 = row2.createCell(i);
			cell1.setCellStyle(style);
			cell1.setCellValue(head[i]);
		}
		++rowIndex;
		
	/*	HSSFCellStyle style1 = wb.createCellStyle();
		// 设置这些样式
		style1.setAlignment(HSSFCellStyle.ALIGN_CENTER);//水平居中 
		style1.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);//垂直居中
		*/
		// Map<String,String> headNameFieldMap = new HashMap<String, String>(); 
		// Map<String,Method> headNameMethodMap = new HashMap<>();
		Map<String,Method> headMethodMap = new HashMap<>();
		
		Method[] methods = beans.get(0).getClass().getMethods();
		Field[] fields = beans.get(0).getClass().getFields();


		//生成Excel内容
		for(int i = 0; i < beans.size(); i++){
			HSSFRow row3 = sheet.createRow(rowIndex++);
			row3.setHeight((short)400);//行高
			ExcelExportMustImpMethodBean studer = beans.get(i);
			Method[] methods = studer.getClass().getMethods();
			Field[] fields = studer.getClass().getFields();
			
			for(int j = 0; j < head.length; j++){
				String headName = head[j];//获取Excel表头
				Method method = headMethodMap.get(headName);

				if(method == null){
					//根据表头获取方法名称
					String methodName = getMethodName(fields,headName);
					//根据方法获取方法名称获取方法
					method = getMethodByName(methods,methodName);
					headMethodMap.put(headName, method);
				}
				
				
				if(method == null){
					continue;
				}
				HSSFCell cellT = row3.createCell(j);
				//cellT.setCellStyle(style1);
				//调用方法设置到Excel中
				setExcelCellValue(studer,cellT,method);
			}
		}
		
		headNameFieldMap.clear();
		headNameMethodMap.clear();
		
		//判断路径是否存在不存在创建目录
		File f = new File(filePath);
		if(!f.getParentFile().exists()){
			f.getParentFile().mkdirs();
		}
		//写入到文件
		wirteFile(wb,filePath);
	}
	
	/**
	 * YangTao  2017年5月3日 15:10:09
	* @Title: getMethodName 
	* @Description: TODO(通过反射获取实体Excel表头和方法对应) 
	* @param @param excelExportMustImpMethodBean
	* @param @param headName
	* @param @return
	* @return String
	 */
	private String getMethodName(Field[] fields,String headName){
		for(Field f : fields){
			ExcelBeanMethodUtil excelBeanMethodUtil = f.getAnnotation(ExcelBeanMethodUtil.class);
			if(excelBeanMethodUtil == null){
				continue;
			}
			if(excelBeanMethodUtil.excelHeadName().equals(headName)){
				return excelBeanMethodUtil.excelHeadMthod();
			}else{
				continue;
			}
		}
		return null;
	}
	/**
	 * YangTao 2017年5月3日 15:25:56
	* @Title: getExcelHeadByBean 
	* @Description: TODO(根据反射获取bean上的ExcelheadName用于生产Excel的head) 
	* @param @param excelExportMustImpMethodBean
	* @return String[]
	 * @throws Exception 
	 */
	public String[] getExcelHeadByBean(ExcelExportMustImpMethodBean excelExportMustImpMethodBean){
		Field[] fields = excelExportMustImpMethodBean.getClass().getFields();
		
		List<String> list = new ArrayList<String>();
		for(Field f : fields){
			ExcelBeanMethodUtil excelBeanMethodUtil = f.getAnnotation(ExcelBeanMethodUtil.class);
			if(excelBeanMethodUtil == null){
				continue;
			}
			list.add(excelBeanMethodUtil.excelHeadName());
		}
		return (String[])list.toArray(new String[list.size()]);
	}
	
	/**
	 * YangTao 2017年4月20日 11:25:18
	* @Title: wirteFile 
	* @Description: TODO(HSSFWorkbook 写入文件) 
	* @param @param outputStream
	* @param @param fileName 需要文件的全路径
	* @return void
	 * @throws IOException 
	 */
	public void wirteFile(HSSFWorkbook wb,String fileName) {
		FileOutputStream output = null;
		try {
			output = new FileOutputStream(fileName);
			wb.write(output);
			output.flush();
			output.close();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}finally{
			if(output != null){
				try {
					output.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}
	
	/**
	 * YangTao 2017年4月20日 11:23:10
	* @Title: getMethodByName 
	* @Description: TODO(根据名字获取方法) 
	* @param @param ms
	* @param @param methodName
	* @param @return
	* @return Method
	 */
	private Method getMethodByName(Method[] ms,String methodName){
		for(int i = 0; i < ms.length; i++){
			if(methodName.equals(ms[i].getName())){
				return ms[i];
			}else{
				continue;
			}
		}
		return null;
	}
	/**
	 * YangTao 2017年4月20日 11:24:27
	* @Title: setExcelCellValue 
	* @Description: TODO(写入值到Excel中，因为类型不太一样 ，所有需要这么处理一下) 
	* @param @param studer
	* @param @param cell
	* @param @param method
	* @return void
	 */
	private void setExcelCellValue(ExcelExportMustImpMethodBean studer, HSSFCell cell,Method method){
		if(method == null){
			cell.setCellValue("");
            return;
		}
		try {
			Object value = method.invoke(studer, new Object[]{});
			if (value == null) {
                cell.setCellValue("");
                return;
            } else if (value instanceof Float) {
                cell.setCellValue(((Float) value).doubleValue());
                return;
            }else if (value instanceof Double) {
                cell.setCellValue(((Double) value).doubleValue());
                return;
            } else if (value instanceof BigDecimal) {
                cell.setCellValue(((BigDecimal) value).doubleValue());
                return;
            } else if (value instanceof Date) {
                cell.setCellValue((Date) value);
                return;
            }else if (value instanceof Calendar) {
                cell.setCellValue((Calendar) value);
                return;
            } else if (value instanceof Byte) {
                cell.setCellValue(((Byte) value).intValue());
                return;
            }else if (value instanceof Short) {
                cell.setCellValue(((Short) value).intValue());
                return;
            }else if (value instanceof Integer) {
                cell.setCellValue(((Integer) value).intValue());
                return;
            }else if (value instanceof Long) {
                cell.setCellValue(((Long) value).longValue());
                return;
            } else if (value instanceof BigInteger) {
                cell.setCellValue(((BigInteger) value).doubleValue());
                return;
            }else {
                String fixedValue = value.toString();
                if (fixedValue != null) {
                    fixedValue = fixedValue.replaceAll("\r\n", "\n");
                }
                if( fixedValue.length() == 0 ){
                    cell.setCellValue("");
                }else{
                    cell.setCellValue(fixedValue);
                }
            }
			
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			e.printStackTrace();
		}
		
	}

}